// in server1.js const http = require("http"); // reference: Node.js HTTP Module const server = http.createServer((request, response) => { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("<h1>Hello World!</h1>"); response.end(); }); server.listen(8080); // Use your port number instead of 8080.How to run?
$ node server1.js
in the command-line interfacehttp://cs.tru.ca:8080
or http://198.162.21.132:8080
on a web browser, not https.
What do you see? Big 'Hello Wrold!'?
require()
do?.listen()
do?.createServer()
?request
and response
, are passed.
request
holds all the information related to the HTTP request sent from a client, and
response
is used to send data back to the client.request
, Node.js IncomingMessage Object
For more information about response
, Node.js HTTP ServerResponse Object
exports
server2.js
into a module?// server2.js const PORT_NO = 8080; // Use your port number, not 8080 const http = require('http'); const start = function() { const server = http.createServer( (request, response) => { // request: from the client; response: to the client response.writeHead(200, {"Content-Type": "text/plain"}); response.write("<h1>Hello World!</h1>"); response.end(); } ); const.listen(PORT_NO); } // Something more exports.start = start;
index2.js
?// index.2.js const server = require('./server2'); // server2.js; the variable server represents all the exported functions in server2.js server.start(); // .start() is the function that is defined in server2.js and exported.
$ node ./index2
request
and response
to Router?router3.js
const route = function(request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); // Plain text, not html text, will be sent back to the client response.write("<h1>Hello World!</h1>"); response.end(); } exports.route = route;
index3.js
, and pass it to the server.index3.js
const server = require('./server3'); const router = require('./router3'); server.start(router);
server3.js
const PORT_NO = 8080; // Use your port number, not 8080 const http = require('http'); const start = function(router) { // Do we have to require 'router'? const server = http.createServer( (request, response) => { // request: from the client; response: to the client router.route(request, response); } ); server.listen(PORT_NO); } // Something more exports.start = start;
const server = require('./server'); const router = require('./router'); server.start(router);
const PORT_NO = 8080; // Use your port number const http = require('http'); const start = function(router) { const server = http.createServer( (request, response) => { // request: from the client; response: to the client router.route(request, response); } ); server.listen(PORT_NO); } // Something more exports.start = start;
const route = function(request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); // Plain text, not html text, will be sent back to the client response.write("<h1>Hello World!</h1>"); response.end(); } exports.route = route;
request
?
(Note that pathname obtained from url.parse(request.url).pathname
starts with '/'.)
const url = require("url"); // reference: Node.js URL Module const route = function (request, response) { const pathname = decodeURI(url.parse(request.url).pathname); // decodeURI(): a JS built-in function // reference: JavaScript decodeURI() response.writeHead(200, {"Content-Type": "text/html"}); // text/html, not text/plain, in this example response.write("<h1>Hello World!</h1><br>"); response.write(pathname + "<br>"); response.end(); } exports.route = route;
request.url
, so that
TRUWSJS can access the resource.
"tilde-expansion"
module.
After you install the module as $ npm install tilde-expansion
in the current working directory,
const tilde = require("tilde-expansion"); // reference: tilde-expansion tilde(username, function(expanded) { // E.g., "~tom" -> "/home/students/tom" console.log(expanded); });
request.url
.request.url
..sjs
files.
.sjs
files..sjs
files..sjs
files:
proceed()
should be exported.
This function is the starting point in a server-side JS program, like main()
in Java.
// In each .sjs file, // _GET: object for the GET data // _POST: object for the POST data // callback: callback function to pass a message back to the client const proceed = function(_GET, _POST, callback) { ... } exports.proceed = proceed;
proceed()
, the callback function should be used to send any message back to the client.
.proceed()
will be invoked to execuse them.
The return message from .proceed()
will be sent back to the client.
proceed()
,
in which the application code is fully responsible how to use request
and how to send messages or data back to the client.const handler = async function(request, response) { ... } export handler;
request.url
?const url = require('url'); // reference: Node.js URL Module const route = function (request, response) { const pathname = decodeURI(url.parse(request.url).pathname); // encodeURI(), decodeURI() // What does decodeURI() do? ... }
$ npm install tilde-expansion
const tilde = require('tilde-expansion'); // reference: tilde-expansion const words = pathname.split('/'); // words[0] is '' and words[1] is '~...' because pathname starts with '/'. E.g, /~tom/... if (words[1] != undefined && words[???][???] == '~') // e.g., pathname is /~tom/... tilde(words[1], function(expanded) { let new_pathname = expanded + '/???'; // 'public_html' should be included. for (let i = 2; i < words.length; i++) new_pathname += '/' + ???; }); else let new_pathname = "/var/www/html" + pathname;
const url = require('url'); const route = function (request, response) { let pathname = decodeURI(url.parse(request.url).pathname); const tilde = require('tilde-expansion'); let words = pathname.split('/'); // words[0] is '' and words[1] is '~...' because pathname starts with '/'. // Case 1 if (words[???] != undefined && words[???][???] == '~') { // e.g., /~tom/... => '', '~tom', ... tilde(words[1], function(expanded) { // Note that a callback function is used. let new_pathname = expanded + '/???'; // 'public_html' should be included. for (let i = 2; i < words.length; i++) new_pathname += '/' + ???; ???? }); ???? // really necessary? } // Case 2 else { let new_pathname = "/var/www/html" + pathname; ???? } } const proceed_with_resolved_pathname = function (req, res, pathname) { ???? // send the pathname to the client }
if (pathname.endsWith("/")) { pathname = pathname + "/index.html"; ... }
const url = require('url'); function route(request, response) { let pathname = decodeURI(url.parse(request.url).pathname); let tilde = require('tilde-expansion'); let words = pathname.split('/'); // words[0] is '' and words[1] is '~...' because pathname starts with '/'. // Case 1 if (words[1] != undefined && words[1][0] == '~') { // e.g., /~tom/... tilde(words[1], function(expanded) { // Note that a callback function is used. let new_pathname = expanded + '/???'; // 'public_html' should be included. for (let i = 2; i < words.length; i++) new_pathname += '/' + words[i]; proceed_with_resolved_pathname(request, response, new_pathname); }); } // Case 2 else { let new_pathname = "/var/www/html" + pathname; proceed_with_resolved_pathname(request, response, new_pathname); } } function proceed_with_resolved_pathname(req, res, pathname) { // Case 3 ???? // what if pathname ends with '/'? res.writeHead(200, {"Content-Type": "text/html"}); // text/html, not text/plain, in this example res.write("<h1>Hello World!</h1><br>"); res.write(??? + "<br>"); res.end(); }
const path = require("path"); // reference: Node.js Path Module let fileordirname = path.basename(pathname); let words = fileordirname.split("."); if (words.length > 1) { let extension = words[words.length - 1]; ... } else { ... }
const path = require("path"); let fileordirname = path.basename(pathname); let words = fileordirname.split("."); let extension; if (words.length > 1) { extension = words[words.length - 1]; } else { pathname = ???? extension = ???? } ...
const url = require('url'); function route(request, response) { let pathname = decodeURI(url.parse(request.url).pathname); let tilde = require('tilde-expansion'); let words = pathname.split('/'); // words[0] is '' and words[1] is '~...' because pathname starts with '/'. // Case 1 if (words[1] != undefined && words[1][0] == '~') { // e.g., /~tom/... tilde(words[1], function(expanded) { // Note that a callback function is used. let new_pathname = expanded + '/???'; // 'public_html' should be included. for (let i = 2; i < words.length; i++) new_pathname += '/' + words[i]; proceed_with_resolved_pathname(request, response, new_pathname); }); } // Case 2 else { let new_pathname = "/var/www/html" + pathname; proceed_with_resolved_pathname(request, response, new_pathname); } } function proceed_with_resolved_pathname(req, res, pathname) { // Case 3 if (pathname.endsWith("/")) pathname = pathname + "/index.html"; // Case 4 ???? res.writeHead(200, {"Content-Type": "text/html"}); // text/html, not text/plain, in this example res.write("<h1>Hello World!</h1><br>"); res.write("Pathname: " + ??? + "<br>"); res.write("File extension: " + ??? + "<br>"); res.end(); }
<HTML> <HEAD> <meta HTTP-EQUIV="REFRESH" content="0; url=http://www.tru.ca:80/science/programs/compsci.html"> </HEAD> </HTML>
response.writeHead(301, {'Location': different_location});
const fs = require('fs'); const filename = 'test.html'; fs.readFile(filename, 'utf8', function(err, content) { if (!err) { console.log(content); } else { console.log(err); } });
router.js
.if (extension != 'sjs' && extension != 'php') { // Let's not send server-side code back. const fs = require('fs'); // reference: Node.js File System Module if (extension == 'html' || extension == 'htm') content_type = 'text/html'; else if ... ... fs.readFile(pathname, 'utf8', function(err, content) { if (!err) { response.writeHead(200, {'Content-type': content_type}); // 200: OK; important response.write(content); response.end(); } else { response.writeHead(404, {'Content-type': "text/html"}); // 4xx: client error response.end("<html><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p><hr></body></html>"); } }); }
// A server-side JavaScript file, e.g., echo_server.sjs and calculator_server.sjs: // _GET: object for the GET data // _POST: object for the POST data // callback: callback function to pass a message back to the client function proceed(_GET, _POST, callback) { ... } exports.proceed = proceed;
.sjs
?
if (extension == 'sjs') { if (request.method.toLowerCase() == "get") { ... } else if (request.???? == '???') { ... } ... }
'http://test.com/start.html?command=Login&username=foo&password=topsecret'
.decodeURI(url.parse(request.url).pathname)
→ '/start.html'
decodeURI(url.parse(request.url).query)
→ 'command=Login&username=foor&password=topsecret'
let _GET = querystring.parse(decodeURI(url.parse(request.url).query))
→ { command:'Login', username:'foo', password:'topsecret' }
_GET['command']
→ 'Login'
JSON.stringfy()
request
' is an Event Emitter object, and
it will emit the 'data'
event whenever the POST data is received.
When there is no more incoming POST data, the 'end'
event is emitted..on()
method on 'request
' can used to listen to these events.let query = ''; let _POST = {}; // not [] ? request.on('data', function(chunk) { // request is an Event Emitter. query += chunk; }); request.???('end', function() { // the end of the data if (query != '') _POST = ???? // parsing using the 'querystring' module. Check the example in the above 'GET' case. });
_POST
.
//---- TRUWSJS ----
const sjs = ???(pathname); // 'pathname' is a sjs script file. This file is required as a module. For example, test.sjs.
// We assume that all '.sjs' programs have the function, proceed(),
// that is the starting point like main() in Java and C/C++ programs.
// _GET: object for the GET query; _POST: object for the POST query
// For example, { command:'Login', username:'foo', password:'topsecret' }
sjs.proceed(_GET, _POST, function(content) { // callback function to get the result from the sjs program
....
response.???("" + content);
response.???();
});
//---- test.sjs ----
function proceed(_GET, _POST, callback) {
let content;
if (_GET['command'] == 'Login') // For example
...
....
???(content); // Don't forget that this function should pass a message back through callback
}
???.??? = proceed;
try-catch
?throw
?isNaN()
do?const divide = function(x, y) { if (y === 0) // throw new Error({name: 'Divide', message: "Can't divide by zero"}); // or throw {name: 'Divide', message: "Can't divide by zero"}; else return x/y; }; try { let result = divide(4, 2); ... } ??? (e) { console.log(e.???); // Not just e. e.name, e.stack, e.message, ... }
??? { const sjs = require(pathname); // We assume all '.sjs' programs have proceed(). sjs.proceed(_GET, _POST, function(html_content) { .... }); } ??? (err) { .... }
??? { const sjs = require(pathname); // We assume all '.sjs' programs have proceed(). let ended = false; sjs.proceed(_GET, _POST, function(html_content) { if (!ended) { .... // write(), ..., end() delete require.cache[require.resolve(pathname)]; // in order to unload this .sjs module; // https://nodejs.org/api/modules.html#requirecache ended = true; // when the callback function is invoked multiple times from the sjs app, // response.end() is invoked again. // It causes an error that cannot be caught. } }); } catch (err) { .... ???[???]; // in order to unload this .sjs module }
const https = require('https'); const fs = require('fs'); let options = { key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'), // Key cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem') // Certificate }; https.???(options, function (req, res) { // similar to http res.writeHead(200); res.end("Hello world!\n"); }).???(8443);
const https = require('https'), pem = require('pem'); pem.createCertificate({days:100, selfSigned:true}, function(err, keys) { if (!err) https.???({key: keys.serviceKey, cert: keys.certificate}, function(req, res) { res.writeHead(200); res.end("Hello world!\n") }).???(8443); });
const http = require('http'); const https = require('https'); const pem = require('pem'); //const ws_server = require('./ws_server'); function start(route) { // HTTP server const server = http.???(function(request, response) { route(request, response); }); server.???(8080); // WebSocket server integrated with HTTP server // It will be discussed later. //ws_server.start(server); // WebSocket server: ws Node.js module // HTTPS server pem.createCertificate({days:100, selfSigned:true}, function(err, keys) { if (!err) https.???({key: keys.serviceKey, cert: keys.certificate}, function(request, response) { ???(???, ???); }).???(8443); }); } ???.start = start;